<script lang="ts" setup>
import { ref } from 'vue'
import CryptoJS from 'crypto-js'

const plainText = ref('')
const encryptedText = ref('')
const decryptedText = ref('')
const secretKey = ref('')
const iv = ref('')
const mode = ref('CBC') // CBC, ECB, CFB, OFB, CTR
const padding = ref('Pkcs7') // Pkcs7, NoPadding, AnsiX923, Iso10126, ZeroPadding
const keySize = ref(256) // 128, 192, 256
const outputFormat = ref('Base64') // Base64, Hex
const errorMessage = ref('')
const isSuccess = ref(false)
const useRandomIV = ref(true)

const modes = [
  { value: 'CBC', label: 'CBC (Cipher Block Chaining)' },
  { value: 'ECB', label: 'ECB (Electronic Codebook)' },
  { value: 'CFB', label: 'CFB (Cipher Feedback)' },
  { value: 'OFB', label: 'OFB (Output Feedback)' },
  { value: 'CTR', label: 'CTR (Counter)' }
]

const paddings = [
  { value: 'Pkcs7', label: 'PKCS#7' },
  { value: 'NoPadding', label: 'No Padding' },
  { value: 'AnsiX923', label: 'ANSI X9.23' },
  { value: 'Iso10126', label: 'ISO 10126' },
  { value: 'ZeroPadding', label: 'Zero Padding' }
]

// 生成随机密钥
function generateRandomKey() {
  const keyLength = keySize.value / 8 // 转换为字节长度
  const randomBytes = CryptoJS.lib.WordArray.random(keyLength)
  secretKey.value = randomBytes.toString(CryptoJS.enc.Hex)
  errorMessage.value = '随机密钥生成成功 ✓'
  isSuccess.value = true
}

// 生成随机IV
function generateRandomIV() {
  const randomBytes = CryptoJS.lib.WordArray.random(16) // AES块大小为16字节
  iv.value = randomBytes.toString(CryptoJS.enc.Hex)
  errorMessage.value = '随机IV生成成功 ✓'
  isSuccess.value = true
}

// AES加密
function encryptText() {
  try {
    if (!plainText.value.trim()) {
      errorMessage.value = '请输入要加密的文本'
      isSuccess.value = false
      return
    }
    
    if (!secretKey.value.trim()) {
      errorMessage.value = '请输入密钥'
      isSuccess.value = false
      return
    }
    
    // 验证密钥长度
    const expectedKeyLength = keySize.value / 4 // Hex字符长度
    if (secretKey.value.length !== expectedKeyLength) {
      errorMessage.value = `密钥长度错误，${keySize.value}位密钥需要${expectedKeyLength}个十六进制字符`
      isSuccess.value = false
      return
    }
    
    // 准备密钥
    const key = CryptoJS.enc.Hex.parse(secretKey.value)
    
    // 准备加密选项
    const options: any = {
      mode: (CryptoJS.mode as any)[mode.value],
      padding: (CryptoJS.pad as any)[padding.value]
    }
    
    // 处理IV（除ECB模式外都需要IV）
    if (mode.value !== 'ECB') {
      if (useRandomIV.value) {
        generateRandomIV()
      }
      
      if (!iv.value.trim()) {
        errorMessage.value = `${mode.value}模式需要IV向量`
        isSuccess.value = false
        return
      }
      
      if (iv.value.length !== 32) { // 16字节 = 32个十六进制字符
        errorMessage.value = 'IV长度错误，需要32个十六进制字符（16字节）'
        isSuccess.value = false
        return
      }
      
      options.iv = CryptoJS.enc.Hex.parse(iv.value)
    }
    
    // 执行加密
    const encrypted = CryptoJS.AES.encrypt(plainText.value, key, options)
    
    // 输出格式化
    if (outputFormat.value === 'Base64') {
      encryptedText.value = encrypted.toString()
    } else {
      encryptedText.value = encrypted.ciphertext.toString(CryptoJS.enc.Hex)
    }
    
    errorMessage.value = '加密成功 ✓'
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `加密失败: ${(error as Error).message}`
    isSuccess.value = false
    encryptedText.value = ''
  }
}

// AES解密
function decryptText() {
  try {
    if (!encryptedText.value.trim()) {
      errorMessage.value = '请输入要解密的文本'
      isSuccess.value = false
      return
    }
    
    if (!secretKey.value.trim()) {
      errorMessage.value = '请输入密钥'
      isSuccess.value = false
      return
    }
    
    // 验证密钥长度
    const expectedKeyLength = keySize.value / 4
    if (secretKey.value.length !== expectedKeyLength) {
      errorMessage.value = `密钥长度错误，${keySize.value}位密钥需要${expectedKeyLength}个十六进制字符`
      isSuccess.value = false
      return
    }
    
    // 准备密钥
    const key = CryptoJS.enc.Hex.parse(secretKey.value)
    
    // 准备解密选项
    const options: any = {
      mode: (CryptoJS.mode as any)[mode.value],
      padding: (CryptoJS.pad as any)[padding.value]
    }
    
    // 处理IV
    if (mode.value !== 'ECB') {
      if (!iv.value.trim()) {
        errorMessage.value = `${mode.value}模式需要IV向量`
        isSuccess.value = false
        return
      }
      
      if (iv.value.length !== 32) {
        errorMessage.value = 'IV长度错误，需要32个十六进制字符（16字节）'
        isSuccess.value = false
        return
      }
      
      options.iv = CryptoJS.enc.Hex.parse(iv.value)
    }
    
    // 准备密文
    let ciphertext
    if (outputFormat.value === 'Base64') {
      ciphertext = encryptedText.value
    } else {
      // Hex格式需要转换
      const hexCiphertext = CryptoJS.enc.Hex.parse(encryptedText.value)
      ciphertext = CryptoJS.enc.Base64.stringify(hexCiphertext)
    }
    
    // 执行解密
    const decrypted = CryptoJS.AES.decrypt(ciphertext, key, options)
    decryptedText.value = decrypted.toString(CryptoJS.enc.Utf8)
    
    if (!decryptedText.value) {
      errorMessage.value = '解密失败，请检查密钥、IV或密文是否正确'
      isSuccess.value = false
      return
    }
    
    errorMessage.value = '解密成功 ✓'
    isSuccess.value = true
  } catch (error) {
    errorMessage.value = `解密失败: ${(error as Error).message}`
    isSuccess.value = false
    decryptedText.value = ''
  }
}

// 复制到剪贴板
function copyToClipboard(text: string, type: string) {
  if (text) {
    navigator.clipboard.writeText(text).then(() => {
      errorMessage.value = `${type}已复制到剪贴板 ✓`
      isSuccess.value = true
    })
  }
}

// 清空所有
function clearAll() {
  plainText.value = ''
  encryptedText.value = ''
  decryptedText.value = ''
  secretKey.value = ''
  iv.value = ''
  errorMessage.value = ''
  isSuccess.value = false
}

// 加载示例
function loadSample() {
  plainText.value = 'Hello, World! 这是一个AES加密测试文本。'
  generateRandomKey()
  if (mode.value !== 'ECB') {
    generateRandomIV()
  }
}

// 交换加密解密文本
function swapTexts() {
  const temp = plainText.value
  plainText.value = decryptedText.value
  decryptedText.value = temp
  
  // 清空中间结果
  encryptedText.value = ''
  errorMessage.value = '文本已交换 ✓'
  isSuccess.value = true
}
</script>

<template>
  <div class="aes-tool">
    <div class="config-section">
      <h3>AES加密配置</h3>
      <div class="config-grid">
        <div class="config-item">
          <label>密钥长度:</label>
          <select v-model="keySize" class="config-select">
            <option :value="128">128位</option>
            <option :value="192">192位</option>
            <option :value="256">256位</option>
          </select>
        </div>
        
        <div class="config-item">
          <label>加密模式:</label>
          <select v-model="mode" class="config-select">
            <option v-for="m in modes" :key="m.value" :value="m.value">
              {{ m.label }}
            </option>
          </select>
        </div>
        
        <div class="config-item">
          <label>填充方式:</label>
          <select v-model="padding" class="config-select">
            <option v-for="p in paddings" :key="p.value" :value="p.value">
              {{ p.label }}
            </option>
          </select>
        </div>
        
        <div class="config-item">
          <label>输出格式:</label>
          <select v-model="outputFormat" class="config-select">
            <option value="Base64">Base64</option>
            <option value="Hex">十六进制</option>
          </select>
        </div>
      </div>
    </div>

    <div class="key-section">
      <h3>密钥和IV配置</h3>
      <div class="key-grid">
        <div class="key-item">
          <label>密钥 ({{ keySize }}位，{{ keySize / 4 }}个十六进制字符):</label>
          <div class="key-input-group">
            <input 
              v-model="secretKey" 
              type="text" 
              class="key-input"
              :placeholder="`输入${keySize}位密钥的十六进制表示...`"
              :maxlength="keySize / 4"
            >
            <button class="btn btn-info" @click="generateRandomKey">🎲 随机生成</button>
          </div>
        </div>
        
        <div class="key-item" v-if="mode !== 'ECB'">
          <label>初始化向量 IV (16字节，32个十六进制字符):</label>
          <div class="key-input-group">
            <input 
              v-model="iv" 
              type="text" 
              class="key-input"
              placeholder="输入IV的十六进制表示..."
              maxlength="32"
            >
            <button class="btn btn-info" @click="generateRandomIV">🎲 随机生成</button>
          </div>
          <div class="checkbox-group">
            <label class="checkbox-item">
              <input type="checkbox" v-model="useRandomIV">
              <span>加密时自动生成随机IV</span>
            </label>
          </div>
        </div>
      </div>
    </div>

    <div class="controls">
      <button class="btn btn-primary" @click="encryptText">🔒 加密</button>
      <button class="btn btn-primary" @click="decryptText">🔓 解密</button>
      <button class="btn btn-info" @click="swapTexts">🔄 交换文本</button>
      <button class="btn btn-warning" @click="loadSample">📝 加载示例</button>
      <button class="btn btn-danger" @click="clearAll">🗑️ 清空</button>
    </div>

    <div class="status" v-if="errorMessage" :class="{ 'error': !isSuccess, 'success': isSuccess }">
      {{ errorMessage }}
    </div>

    <div class="editor-container">
      <div class="editor-section">
        <h3>原文</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="plainText" 
            class="text-input"
            placeholder="请输入要加密的文本..."
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(plainText, '原文')"
            :disabled="!plainText"
          >
            📋
          </button>
        </div>
      </div>

      <div class="editor-section">
        <h3>密文</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="encryptedText" 
            class="text-output"
            placeholder="加密后的文本将显示在这里..."
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(encryptedText, '密文')"
            :disabled="!encryptedText"
          >
            📋
          </button>
        </div>
      </div>

      <div class="editor-section">
        <h3>解密结果</h3>
        <div class="textarea-wrapper">
          <textarea 
            v-model="decryptedText" 
            class="text-output"
            placeholder="解密后的文本将显示在这里..."
            readonly
            spellcheck="false"
          ></textarea>
          <button 
            class="btn btn-success btn-sm copy-btn" 
            @click="copyToClipboard(decryptedText, '解密结果')"
            :disabled="!decryptedText"
          >
            📋
          </button>
        </div>
      </div>
    </div>

    <div class="help-section">
      <details>
        <summary>AES加密说明</summary>
        <div class="help-content">
          <h4>加密模式说明:</h4>
          <ul>
            <li><strong>CBC:</strong> 密码块链接模式，需要IV，安全性高</li>
            <li><strong>ECB:</strong> 电子密码本模式，不需要IV，安全性较低</li>
            <li><strong>CFB:</strong> 密码反馈模式，需要IV，适合流数据</li>
            <li><strong>OFB:</strong> 输出反馈模式，需要IV，适合流数据</li>
            <li><strong>CTR:</strong> 计数器模式，需要IV，可并行处理</li>
          </ul>
          <h4>密钥和IV要求:</h4>
          <ul>
            <li>密钥必须是十六进制格式，长度根据选择的位数确定</li>
            <li>IV必须是32个十六进制字符（16字节）</li>
            <li>建议使用随机生成的密钥和IV以确保安全性</li>
            <li>相同的密钥和IV组合会产生相同的加密结果</li>
          </ul>
          <h4>安全建议:</h4>
          <ul>
            <li>使用256位密钥以获得最高安全性</li>
            <li>推荐使用CBC或CTR模式</li>
            <li>每次加密都应使用不同的IV</li>
            <li>妥善保管密钥，不要在代码中硬编码</li>
          </ul>
        </div>
      </details>
    </div>
  </div>
</template>

<style scoped>
.aes-tool {
  width: 100%;
}

.config-section,
.key-section {
  margin-bottom: 20px;
  padding: 20px;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.config-section h3,
.key-section h3 {
  margin: 0 0 15px 0;
  color: #fff;
  font-size: 1.1em;
}

.config-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 20px;
}

.key-grid {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.config-item,
.key-item {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.config-item label,
.key-item label {
  color: #ccc;
  font-size: 14px;
  font-weight: 500;
}

.config-select {
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  outline: none;
}

.config-select:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.key-input-group {
  display: flex;
  gap: 10px;
  align-items: center;
}

.key-input {
  flex: 1;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 4px;
  color: #fff;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 14px;
  outline: none;
}

.key-input:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.key-input::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.checkbox-group {
  margin-top: 10px;
}

.checkbox-item {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  color: #ccc;
  font-size: 14px;
}

.checkbox-item input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: #007bff;
}

.checkbox-item:hover {
  color: #fff;
}

.controls {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.btn {
  padding: 8px 16px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s ease;
  color: #fff;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-sm {
  padding: 4px 8px;
  font-size: 12px;
}

.btn-primary {
  background: #007bff;
}

.btn-primary:hover:not(:disabled) {
  background: #0056b3;
}

.btn-success {
  background: #28a745;
}

.btn-success:hover:not(:disabled) {
  background: #1e7e34;
}

.btn-info {
  background: #17a2b8;
}

.btn-info:hover:not(:disabled) {
  background: #117a8b;
}

.btn-warning {
  background: #ffc107;
  color: #212529;
}

.btn-warning:hover:not(:disabled) {
  background: #e0a800;
}

.btn-danger {
  background: #dc3545;
}

.btn-danger:hover:not(:disabled) {
  background: #c82333;
}

.status {
  padding: 12px;
  border-radius: 6px;
  margin-bottom: 20px;
  font-weight: 500;
}

.status.error {
  background: rgba(220, 53, 69, 0.1);
  color: #dc3545;
  border: 1px solid rgba(220, 53, 69, 0.3);
}

.status.success {
  background: rgba(40, 167, 69, 0.1);
  color: #28a745;
  border: 1px solid rgba(40, 167, 69, 0.3);
}

.editor-container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 20px;
  margin-bottom: 20px;
}

.editor-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.editor-section h3 {
  margin: 0;
  color: #fff;
  font-size: 1.1em;
}

.textarea-wrapper {
  position: relative;
  height: 200px;
}

.text-input,
.text-output {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 6px;
  padding: 12px;
  color: #fff;
  font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.5;
  resize: none;
  outline: none;
}

.text-output {
  background: rgba(0, 0, 0, 0.4);
}

.text-input:focus,
.text-output:focus {
  border-color: rgba(255, 255, 255, 0.4);
}

.text-input::placeholder,
.text-output::placeholder {
  color: rgba(255, 255, 255, 0.5);
}

.copy-btn {
  position: absolute;
  top: 8px;
  right: 8px;
}

.help-section {
  margin-top: 20px;
}

.help-section details {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 6px;
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.help-section summary {
  padding: 12px 15px;
  cursor: pointer;
  color: #fff;
  font-weight: 500;
  user-select: none;
}

.help-section summary:hover {
  background: rgba(255, 255, 255, 0.05);
}

.help-content {
  padding: 15px;
  color: #ccc;
}

.help-content h4 {
  margin: 0 0 10px 0;
  color: #fff;
  font-size: 1em;
}

.help-content ul {
  margin: 0 0 15px 0;
  padding-left: 20px;
}

.help-content li {
  margin-bottom: 5px;
  line-height: 1.4;
}

.help-content strong {
  color: #fff;
}

@media (max-width: 768px) {
  .config-grid {
    grid-template-columns: 1fr;
  }
  
  .key-input-group {
    flex-direction: column;
    align-items: stretch;
  }
  
  .editor-container {
    grid-template-columns: 1fr;
  }
  
  .controls {
    justify-content: center;
  }
}
</style>